from django.contrib.auth import authenticate, login, logout
from django.db.models import F
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status, pagination
from rest_framework.utils.urls import replace_query_param, remove_query_param

from .models import Article, Like, User
from .permission import IsOwerReadOnly
from .serializer import ArticleSerializer, LikeSerializer, UserSerializer, LoginSerializer, BookSerializer
# 类视图
from rest_framework.views import APIView
# 通用类视图（使用最多，最方便）
from rest_framework import generics
from elasticsearch import Elasticsearch

es = Elasticsearch([{'host': '192.168.136.130', 'port': 9200}])


# Create your views here.
# 用户列表
class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = []


# 登录
class Login(APIView):
    authentication_classes = []  # 身份验证
    permission_classes = []
    serializer_class = LoginSerializer

    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = authenticate(username=username, password=password)
        if user is not None:
            login(request, user)
            return Response({"detail": "登陆成功"}, status=status.HTTP_200_OK)
        return Response({"detail": "登录失败"}, status=status.HTTP_400_BAD_REQUEST)


# 登出
class LoginOut(APIView):
    permission_classes = (IsAuthenticated,)  # 权限设置，只有通过身份验证的用户才能访问此视图

    def get(self, request):
        logout(request)
        request.session.flush()
        return Response({"msg": "退出成功"})


# 文章列表查全部，新增
class ArticleList(generics.ListCreateAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    permission_classes = (IsAuthenticated,)

    def perform_create(self, serializer):  # 创建新对象时执行额外的逻辑。

        serializer.save(auther=self.request.user)


# 文章删改查单个
class ArticleDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    permission_classes = (IsAuthenticated, IsOwerReadOnly)


# 点赞
class LikeArticle(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, pk):
        article = Article.objects.get(pk=pk)
        user = request.user

        # 检查用户是否已经点赞了这篇文章
        if Like.objects.filter(user=user, article=article).exists():  # 如果有返回Turn，没有返回Flase
            return Response({"detail": "你已经点赞过该文章"}, status=status.HTTP_400_BAD_REQUEST)

        # 创建点赞记录
        Like.objects.create(user=user, article=article)  # 在数据库中创建
        article.like_count = F("like_count") + 1  # 利用F对象给文章数据库中的like_count加一
        # 防止top脏读、脏写
        # article.like_count += 1  # 给文章数据库中的like_count加一
        article.save()  # 保存

        return Response({"detail": "点赞成功"}, status=status.HTTP_200_OK)


# 用户的点赞列表
class LikeList(generics.ListAPIView):
    serializer_class = LikeSerializer
    permission_classes = (IsAuthenticated, IsOwerReadOnly)

    def get_queryset(self):  # 用于获取想要的数据集
        user = self.request.user  # 获取当前用户
        return Like.objects.filter(user=user).order_by('article_id')  # 只返回当前用户的点赞记录


class CommonPagination(pagination.PageNumberPagination):
    page_query_description = '页码'
    page_size_query_description = '每页数量'
    max_page_size = 100
    page_size_query_param = 'size'
    page_size = 10

    # 解决端口映射情况，如果使用绝对路径会获取不到正确的url，所以强制使用相对路径get_full_path
    def get_next_link(self):
        if not self.page.has_next():
            return None
        url = self.request.get_full_path()
        page_number = self.page.next_page_number()
        return replace_query_param(url, self.page_query_param, page_number)

    def get_previous_link(self):
        if not self.page.has_previous():
            return None
        url = self.request.get_full_path()
        page_number = self.page.previous_page_number()
        if page_number == 1:
            return remove_query_param(url, self.page_query_param)
        return replace_query_param(url, self.page_query_param, page_number)


class Book(generics.ListAPIView):
    pagination_class = CommonPagination  # 设置分页类

    def get_queryset(self):
        # 构建 Elasticsearch 查询
        book_name = self.request.query_params.get('name')
        # 获取当前索引中的文档总数
        total_docs_response = es.count(index='book')
        total_docs = total_docs_response['count']

        if book_name:
            search_query = {
                'query': {
                    'match': {
                        'name': book_name
                    }
                }
            }
        else:
            search_query = {
                'query': {
                    'match_all': {}
                },
                "size": total_docs
            }

        # 执行查询
        response = es.search(index='book', body=search_query)

        return response

    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        articles = BookSerializer.from_elasticsearch_response(queryset)
        page = self.paginate_queryset(articles)  # 应用分页
        if page is not None:
            serializer = BookSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = BookSerializer(articles, many=True)
        return Response(serializer.data)